package com.louzhu.gulimall.product.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.louzhu.common.constant.ProductConstant;
import com.louzhu.common.to.SkuHasStockVo;
import com.louzhu.common.to.SkuReductionTo;
import com.louzhu.common.to.SpuBoundsTo;
import com.louzhu.common.to.es.SkuEsModel;
import com.louzhu.common.utils.R;
import com.louzhu.gulimall.product.entity.*;
import com.louzhu.gulimall.product.feign.CouponFeignService;
import com.louzhu.gulimall.product.feign.SearchFeignService;
import com.louzhu.gulimall.product.feign.WareFeignService;
import com.louzhu.gulimall.product.service.*;
import com.louzhu.gulimall.product.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.louzhu.common.utils.PageUtils;
import com.louzhu.common.utils.Query;

import com.louzhu.gulimall.product.dao.SpuInfoDao;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    private SpuInfoDescService spuInfoDescService;
    @Autowired
    private SpuImagesService spuImagesService;
    @Autowired
    private AttrService attrService;
    @Autowired
    private ProductAttrValueService productAttrValueService;
    @Autowired
    private SkuInfoService skuInfoService;
    @Autowired
    private SkuImagesService skuImagesService;
    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Autowired
    private CouponFeignService couponFeignService;
    @Autowired
    private WareFeignService wareFeignService;
    @Autowired
    private SearchFeignService searchFeignService;

    @Autowired
    private CategoryService categoryService;
    @Autowired
    private BrandService brandService;



    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 保存商品信息
     * @param spuSaveVo
     * 第一：保存spu信息
     *          1、保存spu基本信息 pms_spu_info
     *          2、保存spu的描述图片 pms_spu_info_desc
     *          3、保存spu图片集 pms_spu_images
     *          4、保存spu的规格参数（基本属性） pms_product_attr_value
     *          5、保存spu积分信息 调用远程服务gulimall-coupon.gulimall_sms.sms_spu_bounds
     * 第二：保存sku信息
     *         6、sku基本信息 pms_sku_info
     *         7、sku图片信息 pms_sku_images
     *         8、sku销售属性值 pms_sku_sale_attr_value
     *         9、sku优惠信息、满减等信息-- 调用远程服务gulimall-coupon
     *             gulimall_sms.sms_sku_ladder 商品阶梯价格
     *             gulimall_sms.sms_sku_full_reduction 商品满减信息
     *             gulimall_sms.sms_member_price 商品会员价格
     */
    @Transactional
    @Override
    public void saveSpuInfo(SpuSaveVo spuSaveVo) {

        /*
        1、保存spu基本信息 pms_spu_info
         */
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        BeanUtils.copyProperties(spuSaveVo,spuInfoEntity);

        spuInfoEntity.setCreateTime(new Date());
        spuInfoEntity.setUpdateTime(new Date());

        this.saveBaseSpuInfo(spuInfoEntity);


        /*
        2、保存spu的描述图片 pms_spu_info_desc
         */
        List<String> decript = spuSaveVo.getDecript();

        SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
        spuInfoDescEntity.setSpuId(spuInfoEntity.getId());
        spuInfoDescEntity.setDecript(String.join(",",decript));
        System.out.println("spuId------------" + spuInfoDescEntity.getSpuId());
        spuInfoDescService.saveSpuInfoDesc(spuInfoDescEntity);

        /*
        3、保存spu图片集 pms_spu_images
         */
        List<String> images = spuSaveVo.getImages();
        spuImagesService.saveImages(spuInfoEntity.getId(),images);

        /*
        4、保存spu的规格参数（基本属性） pms_product_attr_value
         */
        List<BaseAttrs> baseAttrs = spuSaveVo.getBaseAttrs();
        List<ProductAttrValueEntity> collect = baseAttrs.stream().map(attr -> {
            ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity();
            productAttrValueEntity.setAttrId(attr.getAttrId());
            AttrEntity attrEntity = attrService.getById(attr.getAttrId());
            productAttrValueEntity.setAttrName(attrEntity.getAttrName());
            productAttrValueEntity.setAttrValue(attr.getAttrValues());
            productAttrValueEntity.setQuickShow(attr.getShowDesc());
            productAttrValueEntity.setSpuId(spuInfoEntity.getId());

            return productAttrValueEntity;
        }).collect(Collectors.toList());

        productAttrValueService.saveProductAttr(collect);

        /*
         5、保存spu积分信息 gulimall_sms.sms_spu_bounds
         -- 调用远程服务gulimall-coupon
         想要调用别的服务：
            a.引入 openfeign依赖
            b.编写一个接口，告诉springcloud这个接口需要调用远程服务
            c.声明接口的每一个方法都是调用一个远程服务的那个请求
            d.开启远程调用功能
         */
         Bounds bounds = spuSaveVo.getBounds();
         // 将积分数据拷贝到数据传输对象
        SpuBoundsTo spuBoundsTo = new SpuBoundsTo();
        BeanUtils.copyProperties(bounds,spuBoundsTo);
        // 赋值 spuId
        spuBoundsTo.setSpuId(spuInfoEntity.getId());
        // 调用远程服务接口保存数据
        R r = couponFeignService.saveSpuBounds(spuBoundsTo);
        if(r.getCode() != 0){
            log.error("远程保存spu积分信息失败");
        }


        List<Skus> skus = spuSaveVo.getSkus();
        if(null != skus && skus.size()>0){
            skus.forEach(item ->{
                // 查找默认图片
                String defaultImg = "";
                for (Images image : item.getImages()){
                    if(image.getDefaultImg() == 1){
                        // 该图片是默认图片
                        defaultImg = image.getImgUrl();
                    }
                }
                // 6、sku基本信息 pms_sku_info
                SkuInfoEntity skuInfoEntity = new SkuInfoEntity();// SKU基本信息实体
                BeanUtils.copyProperties(item,skuInfoEntity);
                // 从spu基本信息中获取到品牌ID
                skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
                // 从spu基本信息中获取到分类ID
                skuInfoEntity.setCatelogId(spuInfoEntity.getCatelogId());
                // 销量默认为0
                skuInfoEntity.setSaleCount(0L);
                // 从spu基本信息中获取到商品ID
                skuInfoEntity.setSpuId(spuInfoEntity.getId());
                // 默认图片URL
                skuInfoEntity.setSkuDefaultImg(defaultImg);

                // 保存sku的基本信息
                skuInfoService.saveSkuInfo(skuInfoEntity);

                // 数据插入后回写自增主键到实体类中
                Long skuId = skuInfoEntity.getSkuId();

                // 7、sku图片信息 pms_sku_images
                List<SkuImagesEntity> imagesEntities = item.getImages().stream().map(img -> {
                    // sku 图片实体
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    skuImagesEntity.setSkuId(skuId);
                    skuImagesEntity.setDefaultImg(img.getDefaultImg());
                    skuImagesEntity.setImgUrl(img.getImgUrl());
                    return skuImagesEntity;
                }).filter(entity -> {
                    // 没有图片路径的无需保存，将其过滤掉
                    // 返回true就是需要返回false就是删除
                    return !StringUtils.isEmpty(entity.getImgUrl());
                }).collect(Collectors.toList());

                // 保存图片
                skuImagesService.saveBatch(imagesEntities);

                // 8、sku销售属性值 pms_sku_sale_attr_value
                List<Attr> attr = item.getAttr();// 属性信息
                List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = attr.stream().map(a -> {
                    // 销售属性实体
                    SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
                    BeanUtils.copyProperties(a, skuSaleAttrValueEntity);
                    skuSaleAttrValueEntity.setSkuId(skuId);
                    return skuSaleAttrValueEntity;
                }).collect(Collectors.toList());

                // 保存销售属性
                skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);

                // 9、sku优惠信息、满减等信息-- 调用远程服务gulimall-coupon
                SkuReductionTo skuReductionTo = new SkuReductionTo();// 优惠信息数据传输对象
                BeanUtils.copyProperties(item,skuReductionTo);
                skuReductionTo.setSkuId(skuId);
                if(skuReductionTo.getFullCount() > 0 || skuReductionTo.getFullPrice().compareTo(new BigDecimal("0")) == 1){
                    R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
                    if(r1.getCode() != 0){
                        log.error("远程保存sku优惠信息失败");
                    }
                }
            });
        }
    }

    @Override
    public void saveBaseSpuInfo(SpuInfoEntity spuInfoEntity) {
        this.baseMapper.insert(spuInfoEntity);
    }

    /**
     * 根据查询条件查询spu信息
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        // 查询条件器
        QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();

        /*
        1-查询条件key：模糊查询关键词
         */
        String key =(String) params.get("key");
        if(!StringUtils.isEmpty(key)){
            wrapper.and((w)->{
                w.eq("id",key).or().like("spu_name",key);
            });
        }
        /*
        2-查询条件：状态status（0新建、1已上架、2已下架）
         */
        String status = (String) params.get("status");
        if(!StringUtils.isEmpty(status)){
            wrapper.eq("publish_status",status);
        }
        /*
        3-查询条件brandId：品牌Id
         */
        String brandId = (String) params.get("brandId");
        if(!StringUtils.isEmpty(brandId) && !"0".equalsIgnoreCase(brandId)){
            wrapper.eq("brand_id",brandId);
        }
        /*
        4-查询条件catelogId：三级分类Id
         */
        String catelogId = (String) params.get("catelogId");
        if(!StringUtils.isEmpty(catelogId) && !"0".equalsIgnoreCase(catelogId)){
            wrapper.eq("catelog_id",catelogId);
        }
        /*
        5-分页查询
         */
        IPage<SpuInfoEntity> page = this.page(new Query<SpuInfoEntity>().getPage(params), wrapper);

        return new PageUtils(page);
    }

    /**
     * 商品上架
     * @param spuId
     */
    @Override
    public void up(Long spuId) {

        /*
        组装需要的数据
         */

        // 1 根据spuId查询所有的sku信息和品牌名称分类名称
        List<SkuInfoEntity> skuInfoEntities = skuInfoService.getBySpuId(spuId);
        List<Long> skuIdList = skuInfoEntities.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());

        // 2 查询当前spu的规格属性（每个商品的基本属性是相同的），只查出可以被检索的规格属性
        List<ProductAttrValueEntity> attrValueEntityList = productAttrValueService.baseAttrListForSpu(spuId);
        // 查询出所有的attrId
        List<Long> attrIds = attrValueEntityList.stream().map(item -> {
            return item.getAttrId();
        }).collect(Collectors.toList());
        // 过滤出需要检索的attrId
        List<Long> searchAddrIds = attrService.filterAddrId(attrIds);
        // 将其转换为set集合，方便操作
        Set<Long> searchAddrIdSet = new HashSet<>(searchAddrIds);
        // 在查询出的所有规格属性中过滤出需要检索的那一部分
        List<SkuEsModel.Attrs> skuEsModelAttrs = attrValueEntityList.stream().filter(item -> {
            // 如果当前属性的ID包含在之前过滤出的需要检索的ID集合中，返回 true ，就是需要用的
            return searchAddrIdSet.contains(item.getAttrId());
        }).map(item -> {
            // 将最终的结果封装为 SkuEsModel.Attrs 的集合
            SkuEsModel.Attrs attrs = new SkuEsModel.Attrs();
            // 属性对应。进行属性对拷
            BeanUtils.copyProperties(item, attrs);
            return attrs;
        }).collect(Collectors.toList());

        // 3 远程调用查询库存信息
        // 远程查询库存信息
        Map<Long, Boolean> skuStockResult = null;
        try{
            R skuHasStock = wareFeignService.getSkuHasStock(skuIdList);
            TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>(){};
            // 获取远程调用接口返回数据中封装的库存信息数据
            List<SkuHasStockVo> skuHasStockData = skuHasStock.getData(typeReference);
            skuStockResult = skuHasStockData.stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, item -> item.getHasStock()));
        }catch (Exception e){
            log.error("远程调用库存服务出现异常：" + e);
        }
        Map<Long, Boolean> finalSkuStockResult = skuStockResult;

        // 4 封装sku信息
        List<SkuEsModel> skuEsModelList = skuInfoEntities.stream().map(sku -> {
            SkuEsModel skuEsModel = new SkuEsModel();

            // 属性对拷，先拷贝属性名相同的属性值
            BeanUtils.copyProperties(sku,skuEsModel);

            /*
            属性不对应的单独赋值
             */
            // 价格
            skuEsModel.setSkuPrice(sku.getPrice());
            // 默认图片
            skuEsModel.setSkuImg(sku.getSkuDefaultImg());

            // 库存信息:如果远程调用库存服务查询库存出现异常，finalSkuStockResult为Null ，此时将库存设置为有库存
            if(null == finalSkuStockResult){
                skuEsModel.setHasStock(true);
            }else {
                skuEsModel.setHasStock(finalSkuStockResult.get(sku.getSkuId()));
            }

            // TODO 热度评分，上架默认为0 如需其他需求再扩展
            skuEsModel.setHotScore(0L);
            // 品牌信息：品牌名称、品牌图片
            BrandEntity brandEntity = brandService.getById(skuEsModel.getBrandId());
            skuEsModel.setBrandName(brandEntity.getName());
            skuEsModel.setBrandImg(brandEntity.getLogo());
            // 分类信息
            CategoryEntity categoryEntity = categoryService.getById(skuEsModel.getCatelogId());
            skuEsModel.setCatelogName(categoryEntity.getName());
            // 需要检索的规格属性
            skuEsModel.setAttrs(skuEsModelAttrs);

            return skuEsModel;
        }).collect(Collectors.toList());

        /*
        TODO 将数据发给ES保存 调用远程服务 gulimall-search
         */
        R r = searchFeignService.productUp(skuEsModelList);
        if(r.getCode() == 0){
            // 远程调用成功 TODO 修改spu上架状态
            baseMapper.updatSpuStatus(spuId, ProductConstant.StatusEnum.UP_SPU.getCode());
        }else {
            // 远程调用失败 TODO 重复调用--接口幂等性问题
            log.error("商品上架失败");
        }


    }

}